package com.tool.engine.export.mertics;

import com.tool.engine.export.constant.CollectTypeEnum;
import com.tool.engine.export.mertics.collect.Collect;
import com.tool.engine.export.mertics.collect.NumberRecord;
import com.tool.engine.export.mertics.system.MemorySize;
import com.tool.engine.export.mertics.system.MemoryUsage;
import com.tool.engine.export.mertics.time.ExecutionTime;
import lombok.Data;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

@Data
public class MetricsCollector implements Collector{
    //时间相关
    private AtomicReference<ExecutionTime> totalExecutionTime = new AtomicReference<>();
    //获取数据相关时间
    private AtomicReference<ExecutionTime> fetchExecutionTime = new AtomicReference<>();
    //写入数据相关时间
    private AtomicReference<ExecutionTime> writeExecutionTime = new AtomicReference<>();

    //任务数相关
    private AtomicInteger remainingTask = new AtomicInteger();
    private AtomicInteger processTask = new AtomicInteger();

    // 数据量统计
    private final AtomicLong totalProcessedRecords = new AtomicLong(0);

    // 系统资源统计
    private AtomicReference<MemoryUsage> usage = new AtomicReference<>();
    private AtomicReference<MemorySize> usedMemory = new AtomicReference<>();


    // 批量大小统计
//    private AtomicInteger maxBatchSize = new AtomicInteger(0);
//    private AtomicInteger minBatchSize = new AtomicInteger(Integer.MAX_VALUE);
//    private AtomicDouble avgBatchSize = new AtomicDouble(0);

    private Collect collect;


    public MetricsCollector() {
        totalExecutionTime.set(new ExecutionTime());
        fetchExecutionTime.set(new ExecutionTime());
        writeExecutionTime.set(new ExecutionTime());
        usage.set(new MemoryUsage());
        usedMemory.set(new MemorySize());
    }


    @Override
    public void incrExportTaskCount() {
        remainingTask.incrementAndGet();
    }

    @Override
    public void decrExportTaskCount() {
        remainingTask.decrementAndGet();
    }

    @Override
    public void incrProcessTask() {
        processTask.incrementAndGet();
    }

    @Override
    public void decrProcessTask() {
        processTask.decrementAndGet();
    }

    @Override
    public void incrFetchTime(long costTime, int size) {
        fetchExecutionTime.updateAndGet(fetchExecutionTime.get().createFunction(costTime));
        collect.addValue(costTime, CollectTypeEnum.FETCH.getType(),size);
    }

    @Override
    public void incrWriteTime(long costTime, int size) {
        writeExecutionTime.updateAndGet(writeExecutionTime.get().createFunction(costTime));
        collect.addValue(costTime, CollectTypeEnum.WRITE.getType(),size);
    }

    @Override
    public void incrTotalTime(long costTime) {
        totalExecutionTime.updateAndGet(totalExecutionTime.get().createFunction(costTime));
        collect.addValue(costTime, CollectTypeEnum.TOTAL.getType(), 0);
    }

    @Override
    public void incrCapacity(int dataSize, long bytesSize, long threshold) {
        totalProcessedRecords.addAndGet(dataSize);
        usedMemory.updateAndGet(usedMemory.get().createFunction(bytesSize));
        usage.updateAndGet(usage.get().createFunction(usedMemory.get().getUsedMemorySize(), threshold));
        collect.addValue((usage.get().getUsedUsage()), CollectTypeEnum.MEMORY_USAGE.getType(),dataSize);
    }

    @Override
    public void decrCapacity(long bytesSize, long threshold) {
        usedMemory.updateAndGet(usedMemory.get().createFunction(-bytesSize));
        usage.updateAndGet(usage.get().createFunction(usedMemory.get().getUsedMemorySize(), threshold));
    }

    @Override
    public List<NumberRecord> getCollectValue(int type) {
        return collect.getAll(type);
    }

    @Override
    public long getAvgMemorySize() {
        if(usedMemory.get().getMinMemorySize() > usedMemory.get().getMaxMemorySize()){
            return 0;
        }
        return (usedMemory.get().getMaxMemorySize() + usedMemory.get().getMinMemorySize())/2;
    }

    @Override
    public int getProcessingTaskCount() {
        return processTask.get();
    }


    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("\n========== Metrics Collector Summary ==========\n");
        // 时间相关指标
        sb.append("\n--- Execution Times ---\n");
        sb.append(String.format("  Total Execution Time: %s", totalExecutionTime.get()));
        sb.append("\n");
        sb.append(String.format("  Data Fetch Time: %s", fetchExecutionTime.get()));
        sb.append("\n");
        sb.append(String.format("  Data Write Time: %s", writeExecutionTime.get()));
        sb.append("\n");

        // 任务相关指标
        sb.append("\n--- Task Statistics ---\n");
        sb.append(String.format("  Remaining Tasks: %d", remainingTask.get()));
        sb.append("\n");
        sb.append(String.format("  Currently Processing Tasks: %d", processTask.get()));
        sb.append("\n");
        // 数据量指标
        sb.append("\n--- Data Statistics ---\n");
        sb.append(String.format("  Total Processed Records: %,d", totalProcessedRecords.get()));
        sb.append("\n");
        // 内存使用指标
        sb.append("\n--- Memory Usage ---\n");
        sb.append(String.format("  Memory Usage: %s", usage.get()));
        sb.append("\n");
        sb.append(String.format("  Used Memory: %s", usedMemory.get()));
        sb.append("\n");
        sb.append(String.format("  Average Memory Size: %,d bytes", getAvgMemorySize()));
        sb.append("\n");

        sb.append("\n==========================================\n");
        return sb.toString();
    }
}
